

#include <string>

#include <interface.h>
#include <treeview_filter.h>

/*
 * Método que realiza conexão com o servidor firewall
 * user Usuário do servidor firewall
 * senha Senha do servidor firewall
 * servidor Endereço  do servidor firewall
 * TRUE se conexão realizada. FALSE em caso de falha.
 */
bool INTERFACE::conectar_servidor(string user, string senha, string servidor) {
    int tam;
    struct hostent *host;
    struct sockaddr_in addr;

    host = gethostbyname(servidor.c_str());

    if (!host) {
        return false;
    }

    this->sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    if (this->sock < 0) {
        return false;
    }


    memset(&addr, '\0', sizeof (addr));
    addr.sin_family = AF_INET;
    memcpy(&addr.sin_addr.s_addr, host->h_addr, host->h_length);
    addr.sin_port = htons(PORTA_SERVIDOR);

    /*
     * realiza conexão com o servidor firewall e
     * armazena dados de acesso temporariamente
     */
    if (connect(this->sock, (struct sockaddr *) &addr, sizeof (addr)) >= 0) {

        sprintf(this->msg, "<mensagem><login><user>%s</user><password>%s</password></login></mensagem>", user.c_str(), senha.c_str());
        send(this->sock, this->msg, BUFFER_SERVIDOR, MSG_WAITALL);

        recv(this->sock, this->msg, BUFFER_SERVIDOR, MSG_WAITALL);

        if (!strcmp(this->msg, "<mensagem>Login OK</mensagem>")) {

            if (this->usuario_fw.empty() || this->senha_fw.empty() || this->servidor_fw.empty()) {
                this->servidor_fw.clear();
                this->usuario_fw.clear();
                this->senha_fw.clear();

                this->servidor_fw = servidor;
                this->usuario_fw = user;
                this->senha_fw = senha;
            }

            return true;
        }
    }

    return false;
}

/*
 * Método que faz downloads das regras direto do servidor
 */
void INTERFACE::download_regras_firewall() {
    int flag_erro = 1;

    /* envia mensagem solicitando dados do servidor */
    send(this->sock, "<mensagem><upload></mensagem>", BUFFER_SERVIDOR, MSG_WAITALL);

    /* remove regras armazena atualmente no cliente */
    sprintf(this->msg, "DELETE FROM regras_firewall");

    /* inicia transação */
    this->bd->begin();

    this->bd->query(this->msg);

    /* recebe dados do servidor firewall e armazena */
    do {
        flag_erro = recv(this->sock, this->msg, BUFFER_SERVIDOR, MSG_WAITALL);

        /* Caso ocorra algum erro encerra conexão */
        if (flag_erro < 0) {
            this->mensagem("Erro ao receber regras do servidor.", "Falha ao conectar com o servidor.",
                    Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
            break;
        }

        if (strcmp(this->msg, "<mensagem><fim_upload></mensagem>")) {
            this->bd->query(this->msg);
        }
    } while (strcmp(this->msg, "<mensagem><fim_upload></mensagem>"));

    this->bd->commit();
}

/*
 * Método que solicita a o servidor as interfaces
 * de rede disponivel e a exibe nas combobox das interfaces de rede
 */
void INTERFACE::get_interface() {
    int interfac = 0, tam;
    char *aux;
    string inter;

    aux = new char[20];

    /* cria mensagem de solicitação de interface */
    sprintf(this->msg, "<mensagem><interface></mensagem>");

    /* envia mensagem solicitando interface */
    send(this->sock, this->msg, BUFFER_SERVIDOR, MSG_WAITALL);

    /* recebe interfaces disponiveis no servidor */
    if (recv(this->sock, this->msg, BUFFER_SERVIDOR, MSG_WAITALL) < 0) {
        this->mensagem("Erro ao conectar com servidor.", "Falha ao conectar com servidor.",
                Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
    }

    /* 
     * remove qual quer conteudo que tenha combobox
     * tanto na criação de regras quanto no filtro de pacotes
     */
    this->interface_rede_tabela.remove_all();
    this->interface_rede_fp.remove_all();

    /*
     * extrai todas as interface disponiveis no servido para
     * captura de pacotes ou criação de regra de firewall
     * string recebida no formato <interface>inter</interface>
     */
    while (this->msg[interfac]) {

        /* retira as tag xml */
        if (this->msg[interfac] == '<') {
            while ((this->msg[interfac]) && this->msg[++interfac] != '>');
        }/* Obtem conteudo da tag */
        else if (this->msg[interfac] != '>') {
            tam = 0;
            while ((this->msg[interfac]) && this->msg[interfac] != '<') {
                aux[tam++] = this->msg[interfac++];
            }
            aux[tam] = '\0';
            inter.clear();
            inter.append(aux);

            /* adiciona interface de rede as combobox */
            this->interface_rede_tabela.append(inter);
            this->interface_rede_fp.append(inter);
        } else {
            interfac++;
        }
    }

    delete aux;
}

/*
 * Método que carrega as tabelas cadastra no sistema
 * e adiciona a combobox
 */
void INTERFACE::carrega_tabela() {
    if (this->carregar) {
        string sql;
        vector<vector<string> >::iterator i; /* interador para buscar no BD */
        vector<string> valor; /* recebe conteudo */

        /* sinaliza para ignorar evento */
        this->carregar = false;

        sql.clear();

        sql = "SELECT t_nome FROM tabelas";

        /* consulta as tabelas existem no banco de dados */
        this->bd->query(sql.c_str());

        this->tabela.append("");

        if (this->bd->getStatus()) {
            /* atribui os valores encontrados na combobox das tabelas */
            for (i = this->bd->resultados.begin(); i < this->bd->resultados.end(); i++) {
                valor = *i;
                this->tabela.append(Glib::ustring(valor.at(0)));
            }
        }

        this->tabela.set_active(-1);

        /* aceita evento ao selecionar */
        this->carregar = true;
    }
}

/*
 * Método que carrega os chains corresponde a determinada tabela
 * na combobox "Chains"
 */
void INTERFACE::carrega_chain() {
    string tabela;
    tabela.clear();

    /* captura qual tabela foi seleciona */
    tabela = this->tabela.get_active_text();

    /* verifica se a execução do evento esta liberado e se foi seleciona alguma tabela */
    if (this->carregar && (!tabela.empty())) {
        vector<vector<string> >::iterator i; //interador para buscar no BD
        vector<string> valor; //recebe conteudo
        string sql;

        /* bloqueia a execução do evento */
        this->carregar = false;

        /* mostra apenas as regras existem para a tabela selecionada */
        this->trfirewall.reordena_tabela_chain(tabela, "");

        sql.clear();

        sql = "SELECT c_nome FROM tabelas";
        sql += " INNER JOIN chains_tabela ON tabelas.t_id = chains_tabela.ct_tabela";
        sql += " INNER JOIN chains on chains_tabela.ct_chain = chains.c_id";
        sql += " WHERE t_nome = \"" + tabela + "\"";

        /* consulta a relação de chains para aquela tabela */
        this->bd->query(sql.c_str());

        /* remove conteúdo anterior existem no alvo e no chain*/
        this->chain.remove_all();
        this->alvo.remove_all();

        this->chain.append("");

        if (this->bd->getStatus()) {
            /* atribui os chains correspondente na Combobox "Chains" */
            for (i = this->bd->resultados.begin(); i < this->bd->resultados.end(); i++) {
                valor = *i;
                this->chain.append(Glib::ustring(valor.at(0)));
            }
        }

        this->chain.set_active(-1);
        this->alvo.set_active(-1);

        /* libera evento para nova operação */
        this->carregar = true;
    }
}

/*
 * Método que carrega os alvos referente ao conjuto
 * de tabela e chain selecionado.
 */
void INTERFACE::carrega_target() {
    string chain, table;
    chain.clear();
    table.clear();

    /* carrega a tabela e o chain selecionado */
    chain = this->chain.get_active_text();
    table = this->tabela.get_active_text();

    /* verifica se evento esta habilitado e se uma tabela e um chain foram selecionados */
    if (this->carregar && (!table.empty()) && (!chain.empty())) {
        vector<vector<string> >::iterator i; //interador para buscar no BD
        vector<string> valor; //recebe conteudo

        string sql;

        /* bloqueia a execução do evento */
        this->carregar = false;

        /* mostra todas regras criada para a tabela e chain selecionado */
        this->trfirewall.reordena_tabela_chain(table, chain);

        this->alvo.remove_all();

        sql.clear();

        sql = "SELECT ta_nome FROM target ";
        sql += "INNER JOIN targets_chains_tabela ON target.ta_id = targets_chains_tabela.tct_target ";
        sql += "INNER JOIN chains_tabela ON targets_chains_tabela.tct_chain = chains_tabela.ct_id ";
        sql += "INNER JOIN tabelas ON tabelas.t_id = chains_tabela.ct_tabela ";
        sql += "INNER JOIN chains ON chains.c_id = chains_tabela.ct_chain ";
        sql += "WHERE c_nome = \"" + chain + "\" AND t_nome = \"" + table + "\"";
        sql += (this->politica_padrao.get_active() ? " AND ta_opcao_politica = 1" : "");

        /* Consulta a relação de alvos possiveis para tabela e chain selecionado */
        this->bd->query(sql.c_str());

        this->alvo.append("");

        if (this->bd->getStatus()) {
            /* atribui os alvos correspondentes na Combobox "Alvos" */
            for (i = this->bd->resultados.begin(); i < this->bd->resultados.end(); i++) {
                valor = *i;
                this->alvo.append(Glib::ustring(valor.at(0)));
            }
        }

        this->alvo.set_active(-1);

        /* sinalizar que evento esta liberado */
        this->carregar = true;

        /* chama método para liberar interfaces de entrada ou saida ou ambas*/
        this->carrega_interface_rede();
    }
}

/*
 * Método que carrega opção caso exista para 
 * a target selecionada
 */
void INTERFACE::carrega_option() {
    string target;
    target.clear();

    target = this->alvo.get_active_text();

    /* verifica se evento esta habilitado e se uma target foram selecionados */
    if (this->carregar && (!target.empty())) {
        vector<vector<string> >::iterator i; //interador para buscar no BD
        vector<string> valor; //recebe conteudo

        string sql;

        this->carregar = false;

        sql.clear();

        /* Busca relação de opções disponiveis para este alvo */
        sql = "SELECT ot_nome FROM opcoes_target ";
        sql += "INNER JOIN target ON opcoes_target.ot_target = target.ta_id ";
        sql += "WHERE ta_nome = \"" + target + "\"";

        /* Realiza operação de busca no banco */
        this->bd->query(sql.c_str());

        /* remove as opções do alvo anterior */
        this->opcao_alvo.remove_all();

        this->opcao_alvo.append("");

        /* caso operação de busca ocorra com sucesso*/
        if (this->bd->getStatus()) {
            /* atribui as opções encontradas */
            for (i = this->bd->resultados.begin(); i < this->bd->resultados.end(); i++) {
                valor = *i;
                this->opcao_alvo.append(Glib::ustring(valor.at(0)));
            }
        }

        this->opcao_alvo.set_active(-1);

        /* libera evento change */
        this->carregar = true;
    }
}

/*
 * Método que habilita parametros da opção selecionada
 * esta opção referente a target
 */
void INTERFACE::habilita_parametros_option() {
    string target, opcoes, sql;
    target.clear();
    opcoes.clear();
    sql.clear();

    target = this->alvo.get_active_text();
    opcoes = this->opcao_alvo.get_active_text();

    /*
     * realiza operação se operação for chamada pelo usuario
     * e se for selecionado uma opção referente a target
     */
    if (this->carregar && (!target.empty()) && (!opcoes.empty())) {
        vector<vector<string> >::iterator i; //interador para buscar no BD
        vector<string> valor; //recebe conteudo
        this->carregar = false;

        /* pesquisa se determinada opção e tem parametros */
        sql = "SELECT ot_especificar FROM opcoes_target ";
        sql += "INNER JOIN target ON opcoes_target.ot_target = target.ta_id ";
        sql += "WHERE ta_nome = \'" + target + "\' AND opcoes_target.ot_nome = \'" + opcoes + "\'";

        this->bd->query(sql.c_str());

        if (this->bd->getStatus()) {
            /* atribui os valores BD */
            i = this->bd->resultados.begin();
            valor = *i;

            /* caso 1 opção possui parametro obrigatorio */
            if (valor.at(0) == "1") {
                this->parametros_opcao.set_sensitive(true);
            } else {
                this->parametros_opcao.set_sensitive(false);
            }
        }

        this->carregar = true;
    }
}

/*
 * Método que carrega todos os protocolos disponivel no banco de dados
 */
void INTERFACE::carrega_protocolos() {
    /* executa se não estiver sendo executa acesso ao banco */
    if (this->carregar) {
        string sql;
        vector<vector<string> >::iterator i; //interador para buscar no BD
        vector<string> valor; //recebe conteudo
        this->carregar = false;
        sql.clear();

        /* pesquisa todos os protocolos disponiveis */
        sql = "SELECT p_nome FROM protocolos";

        this->bd->query(sql.c_str());

        this->protocolo.remove_all();
        this->argumento_protocolo.remove_all();

        this->protocolo.append("");

        /* carrega na combobox todos os protocolos disponiveis */
        if (this->bd->getStatus()) {
            /* atribui os valores BD */
            for (i = this->bd->resultados.begin(); i < this->bd->resultados.end(); i++) {
                valor = *i;
                this->protocolo.append(Glib::ustring(valor.at(0)));
            }
        }
        this->carregar = true;
    }
}

/*
 * Método que carrega todos os argumentos do protocolo
 */
void INTERFACE::carrega_argumentos_protocolo() {
    string protocolo;
    bool flag = true;
    protocolo.clear();

    protocolo = this->protocolo.get_active_text();

    /* verifica se foi selecionado um protocolo */
    if (this->carregar && (!protocolo.empty())) {
        string sql;
        vector<vector<string> >::iterator i; //interador para buscar no BD
        vector<string> valor; //recebe conteudo
        this->carregar = false;
        sql.clear();

        /* Verifica se o protocolo aceita a inserção de portas */
        sql = "SELECT p_portas FROM protocolos WHERE p_nome = \'" + protocolo + "\'";

        this->bd->query(sql.c_str());

        if (this->bd->getStatus()) {
            i = this->bd->resultados.begin();
            valor = *i;

            /* Remove dados evitando erros */
            this->porta_destino.set_text("");
            this->porta_origem.set_text("");
            this->not_porta_destino.set_active(false);
            this->not_porta_origem.set_active(false);

            /* Caso permita habilita campos de inserção de portas */
            if (valor.at(0) == "1") {
                this->porta_destino.set_sensitive(true);
                this->porta_origem.set_sensitive(true);
                this->not_porta_destino.set_sensitive(true);
                this->not_porta_origem.set_sensitive(true);
            } else {
                this->porta_destino.set_sensitive(false);
                this->porta_origem.set_sensitive(false);
                this->not_porta_destino.set_sensitive(false);
                this->not_porta_origem.set_sensitive(false);
            }
        }

        sql.clear();

        /* consulta todos os modulos disponiveis para protocolo selecionado */
        sql = "SELECT opcoes_protocolos.op_nome, protocolos.p_portas FROM opcoes_protocolos ";
        sql += "INNER JOIN protocolos ON opcoes_protocolos.op_protocolo = protocolos.p_id ";
        sql += "WHERE protocolos.p_nome = \'" + protocolo + "\'";

        this->bd->query(sql.c_str());

        this->argumento_protocolo.remove_all();

        this->argumento_protocolo.append("");

        if (this->bd->getStatus()) {
            /* carrega todas opções disponivel para protocolo selecionado */
            for (i = this->bd->resultados.begin(); i < this->bd->resultados.end(); i++) {
                valor = *i;
                this->argumento_protocolo.append(Glib::ustring(valor.at(0)));
            }

            this->parametros_protocolo.set_sensitive(true);
        } else {
            this->parametros_protocolo.set_sensitive(false);
        }

        this->carregar = true;
    }
}

/*
 * Método que verifica se para o argumento do protocolo
 * selecionado é necessário inserir parametros
 */
void INTERFACE::habilita_parametros_protocolo() {
    string proto, opcao, sql;
    proto.clear();
    opcao.clear();
    sql.clear();

    proto = this->protocolo.get_active_text();
    opcao = this->argumento_protocolo.get_active_text();

    /*
     * realiza operação se operação for chamada pelo usuario
     */
    if (this->carregar && (!proto.empty()) && (!opcao.empty())) {
        vector<vector<string> >::iterator i; //interador para buscar no BD
        vector<string> valor; //recebe conteudo
        this->carregar = false;

        /* pesquisa se determinada opção e tem parametros */
        sql = "SELECT opcoes_protocolos.op_obrigatoria FROM opcoes_protocolos ";
        sql += "INNER JOIN protocolos ON opcoes_protocolos.op_protocolo = protocolos.p_id ";
        sql += "WHERE protocolos.p_nome = \'" + proto + "\' AND opcoes_protocolos.op_nome = \'" + opcao + "\'";

        this->bd->query(sql.c_str());

        if (this->bd->getStatus()) {
            /* atribui os valores BD */
            i = this->bd->resultados.begin();
            valor = *i;

            /* caso 1 opção possui parametro obrigatorio */
            if (valor.at(0) == "1") {
                this->parametros_protocolo.set_sensitive(true);
            } else {
                this->parametros_protocolo.set_sensitive(false);
                this->parametros_protocolo.set_text("");
            }
        }

        this->carregar = true;
    }
}

/*
 * Método que carrega todos os modulos disponiveis
 */
void INTERFACE::carrega_modulos() {

    /* executa se não estiver sendo executa acesso ao banco */
    if (this->carregar) {
        string sql;
        vector<vector<string> >::iterator i; //interador para buscar no BD
        vector<string> valor; //recebe conteudo
        this->carregar = false;
        sql.clear();

        /* pesquisa todos os modulos disponiveis */
        sql = "SELECT m_nome FROM modulos";

        this->bd->query(sql.c_str());

        this->modulo.remove_all();
        this->argumento_modulo.remove_all();

        this->modulo.append("");

        /* carrega na combobox todos os modulos disponiveis */
        if (this->bd->getStatus()) {
            /* atribui os valores BD */
            for (i = this->bd->resultados.begin(); i < this->bd->resultados.end(); i++) {
                valor = *i;
                this->modulo.append(Glib::ustring(valor.at(0)));
            }
        }
        this->carregar = true;
    }
}

/*
 * Método que carrega argumentos referentes ao modulo
 */
void INTERFACE::carrega_argumentos_mod() {
    string modulos;
    modulos.clear();

    modulos = this->modulo.get_active_text();

    /* verifica se foi selecionado um modulo */
    if (this->carregar && (!modulos.empty())) {
        string sql;
        vector<vector<string> >::iterator i; //interador para buscar no BD
        vector<string> valor; //recebe conteudo
        this->carregar = false;
        sql.clear();

        /* consulta todos os modulos disponiveis para modulo selecionado */
        sql = "SELECT om_nome FROM opcoes_modulos ";
        sql += "INNER JOIN modulos ON opcoes_modulos.om_modulo = modulos.m_id ";
        sql += "WHERE m_nome = \"" + modulos + "\"";

        this->bd->query(sql.c_str());

        this->argumento_modulo.remove_all();

        this->argumento_modulo.append("");

        if (this->bd->getStatus()) {
            /* carrega todas opções disponivel para modulo selecionado */
            for (i = this->bd->resultados.begin(); i < this->bd->resultados.end(); i++) {
                valor = *i;
                this->argumento_modulo.append(Glib::ustring(valor.at(0)));
            }
        }
        this->carregar = true;
    }
}

/*
 * Método que carrega regras utilizadas anteriormente
 * para a filtragem de pacotes
 */
void INTERFACE::carrega_regras_filtro() {
    if (this->carregar) {
        string sql;
        vector<vector<string> >::iterator i; //interador para buscar no BD
        vector<string> valor; //recebe conteudo
        this->carregar = false;
        sql.clear();
        this->regra_fp.remove_all();

        /* pesquisa regras anteriores */
        sql = "SELECT rf_regra FROM regras_filtro";

        this->bd->query(sql.c_str());

        if (this->bd->getStatus()) {
            /* carrega todas as regras inseridas anteriormente para filtragem de pacotes */
            for (i = this->bd->resultados.begin(); i < this->bd->resultados.end(); i++) {
                valor = *i;
                this->regra_fp.append(Glib::ustring(valor.at(0)));
            }
        }
        this->carregar = true;
    }
}

/*
 * Método que habilita radio button ao selecionar chain
 * evitando por exemplo:
 * * utilizar uma interface de saída para uma chain INPUT
 */
void INTERFACE::carrega_interface_rede() {
    if (this->carregar) {
        string sql, chain;
        vector<vector<string> >::iterator i; //interador para buscar no BD
        vector<string> valor; //recebe conteudo
        this->carregar = false;

        sql.clear();
        chain.clear();
        chain = this->chain.get_active_text();

        /* pesquisa que tipo de interface rede chain suporta
         * I - Entrada
         * O - Saida
         * A - Ambos
         */
        sql = "SELECT c_interface FROM chains WHERE c_nome = \"" + chain + "\"";

        this->bd->query(sql.c_str());

        if (this->bd->getStatus()) {
            /* atribui os valores BD */
            i = this->bd->resultados.begin();
            valor = *i;

            /* habilita os respectivos radios button para o chain */
            if (valor.at(0) == "O") {
                this->saida.set_sensitive(true);
                this->saida.set_active();
                this->entrada.set_sensitive(false);
            } else if (valor.at(0) == "I") {
                this->saida.set_sensitive(false);
                this->entrada.set_sensitive(true);
                this->entrada.set_active();
            } else {
                this->saida.set_sensitive(true);
                this->saida.set_active();
                this->entrada.set_sensitive(true);
            }
        }
        this->carregar = true;
    }
}

/*
 * Método que verifica se é uma operação de inserção
 * ou alteração de regras de firewall ou alteração da
 * política padrão
 */
void INTERFACE::insere_altera_regras_firewall() {
    string btn;

    btn.clear();
    btn = this->inserir_regra.get_label();

    /* identifica qual será a operação a partir do rotulo do botão */
    if (btn == BTN_INSERIR_REGRA) {
        this->inserir_regra_firewall();
    } else if ((btn == BTN_ALTERAR_REGRA) && this->politica_padrao.get_active()) {
        this->alterar_politica_padrao_firewall();
    } else if (btn == BTN_ALTERAR_REGRA) {
        this->alterar_regra_firewall();
    }
}

/*
 * Método utilizado para avaliar se os dados da opção do alvo
 * esta correta e verifica também se os paramentos do mesmo esta correto.
 * retorna true se os dados referente ao alvo estiverem corretos
 */
bool INTERFACE::avalia_opcao_alvo() {
    string alvo, opcao_alvo, parametros_opcao, sql;

    alvo = this->alvo.get_active_text();
    opcao_alvo = this->opcao_alvo.get_active_text();
    parametros_opcao = this->parametros_opcao.get_text();

    vector<vector<string> >::iterator i; //interador para buscar no BD
    vector<string> valor; //recebe conteudo

    /* Verifica se não informou opção do alvo */
    if (opcao_alvo.empty()) {

        /* Caso não tenha informado verifica se a mesma e obrigatoria */
        sql.clear();
        sql = "SELECT ta_opcao FROM target WHERE ta_nome = \'" + alvo + "\'";

        this->bd->query(sql.c_str());

        if (this->bd->getStatus()) {
            /* atribui os valores BD */
            i = this->bd->resultados.begin();
            valor = *i;
            if (valor.at(0) != "0") {
                this->mensagem("Erro ao informar dados necessários.", "Para este alvo é necessário informar uma opção.",
                        Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
                return false;
            }
        }
    }

    /*
     * Caso tenha informado opção do alvo
     * verifica se a inserção do parametro e obrigatoria
     * é obrigatoria quando o atributo parametros_opcao e editavel
     */
    if ((!opcao_alvo.empty()) && parametros_opcao.empty() && this->parametros_opcao.get_sensitive()) {
        this->mensagem("Erro ao informar dados necessários.", "Para este alvo e opção é necessário informar um parâmetro.",
                Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
        return false;
    }

    /*
     * Busca os id's das expressoes regulares utilizadas
     * para validar o parametro do alvo
     */
    if ((!opcao_alvo.empty()) && (!parametros_opcao.empty())) {
        sql.clear();

        sql = "SELECT opcoes_target.ot_expressoes, opcoes_target.ot_funcao_extra FROM opcoes_target ";
        sql += "INNER JOIN target ON opcoes_target.ot_target = target.ta_id ";
        sql += "WHERE opcoes_target.ot_nome = \'" + opcao_alvo + "\' ";
        sql += "AND target.ta_nome = \'" + alvo + "\'";

        this->bd->query(sql.c_str());

        if (this->bd->getStatus()) {
            i = this->bd->resultados.begin();
            valor = *i;
            sql.clear();
            alvo.clear();
            sql = valor.at(0);
            alvo = valor.at(1);

            /*
             * Verifica se os parametros da
             * opção esta correto caso não esteja informa erro
             */
            if (this->valida_dados_expressao_regular(sql.c_str(), parametros_opcao.c_str(), alvo.c_str())) {
                return true;
            } else {
                this->mensagem("Erro ao avaliar dados.", "Informe um parametro valido para este alvo.", Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
                return false;
            }
        } else {

            /*
             * Falha ao acessar banco de dados
             */

            this->mensagem("Erro ao validar dados.", "Verifique os parametros deste alvo e tente novamente.", Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
            return false;
        }
    }

    return true;
}

bool INTERFACE::valida_insercao_protocolo() {
    string protocolo, argumento, parametro, sql;

    protocolo = this->protocolo.get_active_text();
    argumento = this->argumento_protocolo.get_active_text();
    parametro = this->parametros_protocolo.get_text();

    vector<vector<string> >::iterator i; //interador para buscar no BD
    vector<string> valor; //recebe conteudo

    if (protocolo.empty() && argumento.empty() && parametro.empty()) {
        return true;
    }

    if ((!protocolo.empty()) && argumento.empty() && parametro.empty()) {
        return true;
    }

    /*
     * Caso tenha selecionado um argumento do protocolo
     * verifica se a inserção do parametro e obrigatoria
     * é obrigatoria quando o atributo parametros_opcao e editavel
     */
    if ((!argumento.empty()) && parametro.empty() && this->parametros_protocolo.get_sensitive()) {
        this->mensagem("Erro ao informar dados necessários.", "Para este protocolo e argumento é necessário informar um parâmetro.",
                Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
        return false;
    }

    /*
     * Busca os id's das expressoes regulares utilizadas
     * para validar o parametro do alvo
     */
    sql.clear();

    sql = "SELECT opcoes_protocolos.op_expressao, opcoes_protocolos.op_funcao_extra FROM opcoes_protocolos ";
    sql += "INNER JOIN protocolos ON opcoes_protocolos.op_protocolo = protocolos.p_id ";
    sql += "WHERE protocolos.p_nome = \'" + protocolo + "\' ";
    sql += "AND opcoes_protocolos.op_nome = \'" + argumento + "\'";

    this->bd->query(sql.c_str());

    if (this->bd->getStatus()) {
        i = this->bd->resultados.begin();
        valor = *i;
        sql.clear();
        protocolo.clear();
        sql = valor.at(0);
        protocolo = valor.at(1);

        /*
         * Verifica se os parametros da
         * opção esta correto caso não esteja informa erro
         */
        if (this->valida_dados_expressao_regular(sql.c_str(), parametro.c_str(), protocolo.c_str())) {
            return true;
        } else {
            this->mensagem("Erro ao avaliar dados.", "Informe um parametro valido para este protocolo.", Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
            return false;
        }
    } else {

        /*
         * Falha ao acessar banco de dados
         */

        this->mensagem("Erro ao validar dados.", "Verifique os parametros deste protocolo e tente novamente.", Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
        return false;
    }
}

/*
 * Método que verifica se os valores das
 * portas ou intervalos de portas estão corretos
 */
bool INTERFACE::valida_insercao_portas() {
    string origem, destino, sql;

    origem.clear();
    destino.clear();
    sql.clear();

    origem = this->porta_origem.get_text();
    destino = this->porta_destino.get_text();

    /* 
     * caso tenha inserido as portas de origem ou destino
     * analiza se esta no formato (1, :122, 122:, 11:122)
     * correto e os valores são validos
     */

    if (!origem.empty()) {
        if (!this->valida_dados_expressao_regular("18,19,20,21", origem.c_str(), "intervalo_portas")) {
            return false;
        }
    }

    if (!destino.empty()) {
        if (!this->valida_dados_expressao_regular("18,19,20,21", destino.c_str(), "intervalo_portas")) {
            return false;
        }
    }

    return true;
}

/*
 * Método que verifica se os dados dos módulos estão corretos
 * retorna True se dados do modulo estiver correto
 */
bool INTERFACE::valida_insercao_modulo() {
    string modulo, argumento_modulo, parametros_modulo, sql;

    modulo = this->modulo.get_active_text();
    argumento_modulo = this->argumento_modulo.get_active_text();
    parametros_modulo = this->parametros_modulo.get_text();

    vector<vector<string> >::iterator i; //interador para buscar no BD
    vector<string> valor; //recebe conteudo

    /*
     * se a "utilização" dos modulos esta correta
     * Esta correta quando informa todos ou nem um modulo, parametro e argumento
     */
    if ((!modulo.empty()) && (!parametros_modulo.empty()) && (!argumento_modulo.empty())) {
        sql.clear();

        sql = "SELECT opcoes_modulos.om_expressoes, opcoes_modulos.om_funcao_extra FROM opcoes_modulos ";
        sql += "INNER JOIN modulos ON opcoes_modulos.om_modulo = modulos.m_id ";
        sql += "WHERE opcoes_modulos.om_nome = \'" + argumento_modulo + "\' ";
        sql += "AND modulos.m_nome = \'" + modulo + "\'";

        this->bd->query(sql.c_str());

        if (this->bd->getStatus()) {

            i = this->bd->resultados.begin();
            valor = *i;
            sql.clear();
            modulo.clear();
            sql = valor.at(0);
            modulo = valor.at(1);

            /*
             * Verifica se os parametros do módulo
             * corretos caso não esteja informa erro
             */
            if (this->valida_dados_expressao_regular(sql.c_str(), parametros_modulo.c_str(), modulo.c_str())) {
                return true;
            } else {
                this->mensagem("Erro ao inserir regra", "Informe um parametro valido para este modulo.",
                        Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
                return false;
            }
        } else {

            /*
             * Falha ao acessar banco de dados
             */

            this->mensagem("Erro ao validar dados.", "Verifique os parametros deste módulo e tente novamente.",
                    Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
            return false;
        }
    } else if (modulo.empty() && parametros_modulo.empty() && argumento_modulo.empty()) {

        /*
         * se não foi informado modulo, parametro do módulo e nem argumento
         * a regra esta correta. pois o utilização do mesmo não é obrigatoria.
         */

        return true;
    } else {

        /*
         * faltou informar pelo menos uma opção
         */

        this->mensagem(
                "Erro ao inserir regra no firewall.",
                "Verifique se a inserção do módulo esta correta e tente novamente.",
                Gtk::MESSAGE_ERROR,
                Gtk::BUTTONS_OK
                );
    }
    return false;
}

/*
 * Método utilizado para verificar de determinada informação esta correta.
 * id_expressao Id's das expressoes regulares utilizada para pesquisar as expressoes para validar os dados
 * valor_verificar Valor que será validado
 * retorna true se os dados são validos
 */
bool INTERFACE::valida_dados_expressao_regular(const char *id_expressao, const char *valor_verificar, const char *funcao_extra) {
    string sql;

    /* aloca espaço para a estrutura do tipo regex_t */
    regex_t reg;

    vector<vector<string> >::iterator i; //interador para buscar no BD
    vector<string> valor; //recebe conteudo
    sql.clear();

    sql = "SELECT expressoes_regulares.er_expressao FROM expressoes_regulares ";
    sql += "WHERE expressoes_regulares.er_id IN (";
    sql.append(id_expressao);
    sql += ")";

    this->bd->query(sql.c_str());

    sql.clear();

    if (this->bd->getStatus()) {
        for (i = this->bd->resultados.begin(); i < this->bd->resultados.end(); i++) {
            valor = *i;
            sql = valor.at(0);

            /*
             * compila a expressão regular retorna pela consulta
             * em caso de erro, a função retorna diferente de zero
             */
            if (regcomp(&reg, sql.c_str(), REG_EXTENDED | REG_NOSUB) != 0) {
                this->mensagem("Falha de Expressão regular",
                        "Corrija a expressão regular inserida no banco e tente novamente.",
                        Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
                return false;
            }

            /*
             * realiza a comparação da ER compilada (&reg) com a valor_verificar 
             * se a função regexec retornar 0 casou, caso contrário não
             */
            if ((regexec(&reg, valor_verificar, 0, (regmatch_t *) NULL, 0)) == 0) {

                if (strcmp(funcao_extra, "intervalo_portas") == 0) {
                    return this->intervalo_portas(valor_verificar);
                } else if (strcmp(funcao_extra, "verifica_portas_dnat_snat") == 0) {
                    return this->verifica_portas_dnat_snat(valor_verificar);
                } else if (strcmp(funcao_extra, "verifica_portas_redirect_masquerade") == 0) {
                    return this->verifica_portas_redirect_masquerade();
                } else {
                    return true;
                }
            }
        }
    }

    return false;
}

/*
 * Método que avalia o intervalo de portas se
 * o valor "minimo" é menor que o "máximo"
 * 55:75 Valido
 * 75:55 Invalido
 */
bool INTERFACE::intervalo_portas(const char *intervalos) {
    string str_min, str_max, aux;
    int min, max, pos, tam;

    aux.clear();
    aux.append(intervalos);

    pos = (int) aux.find(":");
    tam = (int) aux.length();

    /*
     * ignora os formatos 0000, 0000: e :0000
     */
    if ((pos > 0) && ((pos + 1) < tam)) {
        str_min = aux.substr(0, pos);
        str_max = aux.substr((pos + 1));

        /*
         * verifica se o valor da esquerda "Minimo"
         * e menor ou igual que o da direita "Máximo"
         */
        if (atoi(str_min.c_str()) <= atoi(str_max.c_str())) {
            return true;
        } else {
            return false;
        }
    }

    return true;
}

/*
 * Método que verifica se os endereços de origem e destino existem
 */
bool INTERFACE::verifica_endereco(const char *endereco) {
    const char* exp = "^([1-9][0-9]?|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.(([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){2}([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])(/([0-9]|[12][0-9]|3[012]))?$";
    regex_t reg;

    /* compila filtro */
    if (regcomp(&reg, exp, REG_EXTENDED | REG_NOSUB) != 0) {
        return false;
    }

    /*
     * Valida se for um endereço de ip com ou
     * sem mascara de rede é valido
     */
    if ((regexec(&reg, endereco, 0, (regmatch_t *) NULL, 0)) == 0) {
        return true;
    }

    /* Verifica se o endereço informa existe */
    if ((gethostbyname(endereco)) != NULL) {
        return true;
    }

    return false;
}

/*
 * Método que verifica se os dados necessários para os
 * alvos dnat e snat (tabela nat) forma informados
 */
bool INTERFACE::verifica_portas_dnat_snat(const char *endereco) {
    string protocolo, origem, destino, aux;
    int pos;

    aux.clear();
    aux.append(endereco);

    /*
     * caso endereço informado sejá nos formatos
     * 11.1.1.1:111 ou 11.1.1.1-11.1.1.1:1
     * verifica se foi informada as portas e um protocolo
     */
    pos = (int) aux.find(":");

    if (pos > 0) {
        protocolo = this->protocolo.get_active_text();
        origem = this->porta_origem.get_text();
        destino = this->porta_destino.get_text();

        /* Informa mensagem de erro */
        if (protocolo.empty() || (origem.empty() && destino.empty())) {
            this->status.set_text("Selecione um protocolo e informe uma porta.");
            this->mensagem("Erro ao dados requiridos.", "Selecione um protocolo e informe uma porta.", Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
            return false;
        }
    }

    return true;
}

/*
 * Caso sejá inserido paramtro nos alvos
 * REDIRECT ou MASQUERADE
 * verifica se foi selecionado um protocolo
 * e inserido portas de origem ou destino
 */
bool INTERFACE::verifica_portas_redirect_masquerade() {
    string protocolo, origem, destino, aux;

    protocolo = this->protocolo.get_active_text();
    origem = this->porta_origem.get_text();
    destino = this->porta_destino.get_text();

    if (protocolo.empty() || (origem.empty() && destino.empty())) {
        this->status.set_text("Selecione um protocolo e informe uma porta.");
        this->mensagem("Erro ao dados requiridos.", "Selecione um protocolo e informe uma porta.", Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
        return false;
    } else {
        return true;
    }
}

/*
 * Método que verifica se regra de firewall existe
 */
bool INTERFACE::existe_regra_firewall() {
    string linha, tabela, chain, alvo, opcao_alvo, interface_rede_tabela, modulo, argumento_modulo, protocolo;
    string parametros_opcao, endereco_origem, endereco_destino, parametros_modulo, not_endereco_origem;
    string not_protocolo, argumento_protocolo, parametro_protocolo, not_endereco_destino, not_interface, btn, sql;
    string porta_origem, porta_destino, not_porta_origem, not_porta_destino;

    vector<vector<string> >::iterator i; //interador para buscar no BD
    vector<string> valor; //recebe conteudo

    bool entrada;

    btn.clear();
    btn = this->inserir_regra.get_label();

    /* Inicio da Obtenção dos dados inseridos pelo usuário */
    tabela = this->tabela.get_active_text();
    chain = this->chain.get_active_text();
    alvo = this->alvo.get_active_text();

    linha = this->linha.get_text();
    opcao_alvo = this->opcao_alvo.get_active_text();
    parametros_opcao = this->parametros_opcao.get_text();
    endereco_origem = this->endereco_origem.get_text();
    not_endereco_origem = (this->not_endereco_origem.get_active() && (!endereco_origem.empty()) ? "1" : "0");

    endereco_destino = this->endereco_destino.get_text();
    not_endereco_destino = (this->not_endereco_destino.get_active() && (!endereco_destino.empty()) ? "1" : "0");

    porta_origem = this->porta_origem.get_text();
    porta_destino = this->porta_destino.get_text();
    not_porta_origem = (this->not_porta_origem.get_active() && (!porta_origem.empty()) ? "1" : "0");
    not_porta_destino = (this->not_porta_destino.get_active() && (!porta_destino.empty()) ? "1" : "0");

    interface_rede_tabela = this->interface_rede_tabela.get_active_text();
    not_interface = (this->not_interface.get_active() && (!interface_rede_tabela.empty()) ? "1" : "0");
    entrada = this->entrada.get_active();
    modulo = this->modulo.get_active_text();
    argumento_modulo = this->argumento_modulo.get_active_text();
    parametros_modulo = this->parametros_modulo.get_text();

    protocolo = this->protocolo.get_active_text();
    argumento_protocolo = this->argumento_protocolo.get_active_text();
    parametro_protocolo = this->parametros_protocolo.get_text();

    not_protocolo = (this->not_protocolo.get_active() && (!protocolo.empty()) ? "1" : "0");

    /* Final da Obtenção dos dados inseridos pelo usuário */

    this->status.set_text("Verificando dados necessários ...");

    /* Verifica se foi informado pelo menos tabela, chain e alvo */
    if (tabela.empty() || chain.empty() || alvo.empty()) {
        this->status.set_text("Informe ao menos Tabela, Chain e Alvo");
        this->mensagem("Erro ao informar dados necessários.", "Informe ao menos Tabela, Chain e Alvo", Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
        return false;
    }

    this->status.set_text("Verificando endereço de origem ... ");

    if (!endereco_origem.empty()) {
        if (!this->verifica_endereco(endereco_origem.c_str())) {
            this->mensagem("Erro endereço inválido.", "Informe um endereço de origem válido.", Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
            this->status.set_text("Informe um endereço de origem válido.");
            return false;
        }
    }

    this->status.set_text("Verificando endereço de destino ... ");

    if (!endereco_destino.empty()) {
        if (!this->verifica_endereco(endereco_destino.c_str())) {
            this->status.set_text("Informe um endereço de destino válido.");
            this->mensagem("Erro endereço inválido.", "Informe um endereço de destino válido.", Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
            return false;
        }
    }

    this->status.set_text("Verificando portas do protocolo ... ");

    if (!this->valida_insercao_portas()) {
        this->status.set_text("Informe um valor de portas válido.");
        this->mensagem("Erro porta inválido.", "Informe um valor de portas válido.", Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
        return false;
    }

    /*
     * Verifica se foi dados necessário foram informados
     * caso sejam obrigatorios verifica se estão corretos
     */
    this->status.set_text("Verificando dados alvo ...");
    if (!this->avalia_opcao_alvo()) {
        this->status.set_text("");
        return false;
    }

    this->status.set_text("Verificando do protocolo ... ");

    if (!this->valida_insercao_protocolo()) {
        this->status.set_text("");
        return false;
    }

    this->status.set_text("Verificando módulos ... ");

    if (this->valida_insercao_modulo()) {
        sql.clear();

        /* gera sql para verificar se regra já existe ou não */
        sql = "SELECT COUNT(rf_id)";
        sql += " FROM regras_firewall";
        sql += " LEFT JOIN chains_tabela ON regras_firewall.rf_chain_tabela = chains_tabela.ct_id";
        sql += " LEFT JOIN tabelas ON chains_tabela.ct_tabela = tabelas.t_id";
        sql += " LEFT JOIN chains ON chains_tabela.ct_chain = chains.c_id";
        sql += " LEFT JOIN target ON regras_firewall.rf_target = target.ta_id";
        sql += " LEFT JOIN opcoes_target ON target.ta_id = opcoes_target.ot_target";
        sql += " AND regras_firewall.rf_opcao_target = opcoes_target.ot_id";
        sql += " LEFT JOIN opcoes_modulos ON regras_firewall.rf_modulo = opcoes_modulos.om_id";
        sql += " LEFT JOIN modulos ON opcoes_modulos.om_modulo = modulos.m_id";
        sql += " LEFT JOIN opcoes_protocolos ON regras_firewall.rf_protocolo = protocolos.p_id";
        sql += " LEFT JOIN protocolos ON opcoes_protocolos.op_protocolo = protocolos.p_id";
        sql += " AND rf_argumento_protocolo = opcoes_protocolos.op_id";
        sql += " WHERE tabelas.t_nome = \'" + tabela + "\'";
        sql += " AND chains.c_nome = \'" + chain + "\'";
        sql += " AND target.ta_nome = \'" + alvo + "\'";

        /*
         * Caso seja uma operação de alteração adiciona o numero da linha da regra
         * Adicionado para poder identificar quando somente for alterar a linha da regra
         */

        if (btn == BTN_ALTERAR_REGRA) {
            sql += " AND rf_linha = " + linha;
        }

        sql += " AND opcoes_target.ot_nome " + (opcao_alvo.empty() ? "IS NULL" : ("= \'" + opcao_alvo + "\'"));
        sql += " AND rf_parametros_opcao " + ((opcao_alvo.empty() || parametros_opcao.empty()) ? "IS NULL" : ("= \'" + parametros_opcao + "\'"));
        sql += " AND rf_endereco_origem " + (endereco_origem.empty() ? "IS NULL" : ("= \'" + endereco_origem + "\'"));
        sql += " AND rf_not_endereco_origem = " + not_endereco_origem;
        sql += " AND rf_porta_origem " + (porta_origem.empty() ? "IS NULL" : ("= \'" + porta_origem + "\'"));
        sql += " AND rf_not_porta_origem =" + not_porta_origem;

        sql += " AND rf_endereco_destino " + (endereco_destino.empty() ? "IS NULL" : ("= \'" + endereco_destino + "\'"));
        sql += " AND rf_not_endereco_destino = " + not_endereco_destino;
        sql += " AND rf_porta_destino " + (porta_destino.empty() ? "IS NULL" : ("= \'" + porta_destino + "\'"));
        sql += " AND rf_not_porta_destino =" + not_porta_destino;

        sql += " AND rf_interface_rede " + (interface_rede_tabela.empty() ? "IS NULL" : ("= \'" + interface_rede_tabela + "\'"));
        sql += " AND rf_interface_rede_saida_entrada ";
        sql += (interface_rede_tabela.empty() ? "IS NULL" : (entrada ? "= \'i\'" : "= \'o\'"));
        sql += " AND rf_not_interface_rede = " + not_interface;
        sql += " AND modulos.m_nome " + ((modulo.empty() || argumento_modulo.empty()) ? "IS NULL" : ("= \'" + modulo + "\'"));
        sql += " AND opcoes_modulos.om_nome " + ((modulo.empty() || argumento_modulo.empty()) ? "IS NULL" : ("= \'" + argumento_modulo + "\'"));
        sql += " AND rf_parametros_modulo ";
        sql += ((modulo.empty() || argumento_modulo.empty() || parametros_modulo.empty()) ? "IS NULL" : ("= \'" + parametros_modulo + "\'"));

        sql += " AND protocolos.p_nome " + ((protocolo.empty()) ? "IS NULL" : ("= \'" + protocolo + "\'"));
        sql += " AND opcoes_protocolos.op_nome " + (argumento_protocolo.empty() ? "IS NULL" : ("= \'" + argumento_protocolo + "\'"));
        sql += " AND rf_parametros_protocolo " + (parametro_protocolo.empty() ? "IS NULL" : ("= \'" + parametro_protocolo + "\'"));

        sql += " AND rf_not_protocolo = " + not_protocolo;

        this->bd->query(sql.c_str());

        if (this->bd->getStatus()) {
            i = this->bd->resultados.begin();
            valor = *i;

            /*
             * operação e valida se valor retorno igual a 0
             */

            if (valor.at(0) == "0") {
                return true;
            } else {

                /*
                 * Caso a operação seja invalida informa erro ao usuário
                 */
                this->mensagem(
                        "Erro ao inserir regra no firewall.",
                        "Verifique se todos os dados informados estão corretos ou se esta regra já foi inserida.",
                        Gtk::MESSAGE_ERROR,
                        Gtk::BUTTONS_OK
                        );
            }
        }
    }

    return false;
}

/*
 * Método que altera politica padrão de tabela e chain
 */
void INTERFACE::alterar_politica_padrao_firewall() {
    string tabela, chain, alvo, sql;

    tabela = this->tabela.get_active_text();
    chain = this->chain.get_active_text();
    alvo = this->alvo.get_active_text();

    /* Verifica se os dados necessários foram informados */
    if (tabela.empty() || chain.empty() || alvo.empty()) {
        this->mensagem("Erro ao informar dados necessários.",
                "Para criar a política padrão é necessário informar tabela, chain e alvo.",
                Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
    } else {

        /* Realiza a atualização da politica padrão do chains */

        sql = "UPDATE chains_tabela SET ct_politica = ";
        sql += "(SELECT target.ta_id FROM target WHERE target.ta_nome = \"" + alvo + "\") ";
        sql += "WHERE ct_id = (SELECT chains_tabela.ct_id FROM  chains_tabela ";
        sql += "INNER JOIN chains ON chains_tabela.ct_chain = chains.c_id ";
        sql += "INNER JOIN tabelas ON chains_tabela.ct_tabela = tabelas.t_id ";
        sql += "WHERE tabelas.t_nome = \"" + tabela + "\" AND chains.c_nome = \"" + chain + "\")";

        if (!this->bd->query(sql.c_str())) {

            /* Informa erro caso ocorra */

            this->mensagem("Erro", "Erro ao alterar política padrão, verifique dados e tente novamente",
                    Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
        } else {
            /*
             * exibe politicas atualizadas
             * habilita apenas opções necessárias
             * mostra todas as politícas
             * sinaliza que ouve uma alteração
             */
            this->trfirewall.get_politica_padrao();
            this->opcoes_gera_politica_padrao();
            this->trfirewall.reordena_tabela_chain("", "");
            this->servidor_atualizado = false;
        }
    }
}

/*
 * Método utilizado para inserir uma nova
 * regra de firewall
 */
void INTERFACE::inserir_regra_firewall() {
    string linha, tabela, chain, alvo, opcao_alvo, interface_rede_tabela, modulo, argumento_modulo, protocolo;
    string parametros_opcao, endereco_origem, endereco_destino, not_endereco_origem, not_interface;
    string not_protocolo, not_endereco_destino, argumento_protocolo, parametro_protocolo, sql;
    string porta_origem, porta_destino, not_porta_origem, not_porta_destino;

    /* Antes de inserir verifica-se regra já existe e se alguns parametros foram informados */
    if (this->existe_regra_firewall()) {

        /* caso não exista - obtem dados para sua inserção*/
        tabela = this->tabela.get_active_text();
        chain = this->chain.get_active_text();
        alvo = this->alvo.get_active_text();

        linha = this->linha.get_text();
        opcao_alvo = this->opcao_alvo.get_active_text();
        parametros_opcao = this->get_parametros_opcao_alvo();

        endereco_origem = this->get_endereco_origem();
        not_endereco_origem = (this->not_endereco_origem.get_active() && (!endereco_origem.empty()) ? "1" : "0");
        endereco_destino = this->get_endereco_destino();
        not_endereco_destino = (this->not_endereco_destino.get_active() && (!endereco_destino.empty()) ? "1" : "0");

        porta_origem = this->porta_origem.get_text();
        porta_destino = this->porta_destino.get_text();
        not_porta_origem = (this->not_porta_origem.get_active() && (!porta_origem.empty()) ? "1" : "0");
        not_porta_destino = (this->not_porta_destino.get_active() && (!porta_destino.empty()) ? "1" : "0");

        interface_rede_tabela = this->get_interface_rede_firewall();
        not_interface = (this->not_interface.get_active() && (!interface_rede_tabela.empty()) ? "1" : "0");
        modulo = this->modulo.get_active_text();
        argumento_modulo = this->argumento_modulo.get_active_text();

        protocolo = this->protocolo.get_active_text();
        argumento_protocolo = this->argumento_protocolo.get_active_text();
        parametro_protocolo = this->parametros_protocolo.get_text();

        not_protocolo = (this->not_protocolo.get_active() && (!protocolo.empty()) ? "1" : "0");

        /* Operação é realizada utilizando transaction - caso ocorra erro cancela alteração */

        this->bd->begin();

        sql.clear();

        sql = "INSERT INTO regras_firewall VALUES(NULL";

        /*
         * Query que verifica o ultima linha do conjunto tabela, chain e alvo
         * e adiciona na proxima linha. Se chain estiver vazio insere na primeira linha
         */
        sql += ", (SELECT CASE WHEN MAX(rf_linha) IS NULL THEN 1 ";
        sql += ((linha != "0" ? "WHEN MAX(rf_linha) >= " + linha + " THEN " + linha + " " : ""));
        sql += "ELSE MAX(rf_linha) + 1 END AS linha ";
        sql += "FROM regras_firewall ";
        sql += "INNER JOIN chains_tabela ON regras_firewall.rf_chain_tabela = chains_tabela.ct_id ";
        sql += "INNER JOIN tabelas ON chains_tabela.ct_tabela = tabelas.t_id ";
        sql += "INNER JOIN chains ON chains_tabela.ct_chain = chains.c_id ";
        sql += "WHERE tabelas.t_nome = \'" + tabela + "\' ";
        sql += "AND chains.c_nome = \'" + chain + "\')";
        /* Fim da inserção na linha */

        /* Inserção de Tabela, chain já são relacionado no banco de dados */
        sql += ", (SELECT chains_tabela.ct_id ";
        sql += "FROM chains_tabela ";
        sql += "INNER JOIN tabelas ON chains_tabela.ct_tabela = tabelas.t_id ";
        sql += "INNER JOIN chains ON chains_tabela.ct_chain = chains.c_id ";
        sql += "WHERE tabelas.t_nome = \'" + tabela + "\' ";
        sql += "AND chains.c_nome = \'" + chain + "\' )";
        /* Inserção de Tabela, chain já são relacionado no banco de dados */

        sql += ", (SELECT target.ta_id FROM target WHERE target.ta_nome = \'" + alvo + "\')";

        if (opcao_alvo.empty()) {
            sql += ", NULL";
        } else {
            sql += ", (SELECT ot_id FROM opcoes_target ";
            sql += "INNER JOIN target ON opcoes_target.ot_target = target.ta_id ";
            sql += "WHERE ta_nome = \'" + alvo + "\' ";
            sql += "AND ot_nome = \'" + opcao_alvo + "\')";
        }

        sql += ", " + parametros_opcao;

        sql += ", " + endereco_origem;
        sql += ", " + not_endereco_origem;
        sql += ", " + (porta_origem.empty() ? "NULL" : "\'" + porta_origem + "\'");
        sql += ", " + not_porta_origem;

        sql += ", " + endereco_destino;
        sql += ", " + not_endereco_destino;
        sql += ", " + (porta_destino.empty() ? "NULL" : "\'" + porta_destino + "\'");
        sql += ", " + not_porta_destino;

        sql += ", " + interface_rede_tabela;
        sql += ", " + this->get_interface_rede_saida_entrada();
        sql += ", " + not_interface;

        if (modulo.empty() || argumento_modulo.empty()) {
            sql += ", NULL, NULL";
        } else {
            sql += ", (SELECT om_id FROM opcoes_modulos ";
            sql += "INNER JOIN modulos ON opcoes_modulos.om_modulo = modulos.m_id ";
            sql += "WHERE m_nome = \'" + modulo + "\' ";
            sql += "AND om_nome = \'" + argumento_modulo + "\') ";
            sql += ", " + this->get_parametros_modulos();
        }

        if (protocolo.empty()) {
            sql += ", NULL, NULL, NULL";
        } else {
            sql += ", (SELECT p_id FROM protocolos WHERE protocolos.p_nome = \'" + protocolo + "\')";

            if (!argumento_protocolo.empty()) {
                sql += ", (SELECT op_id FROM opcoes_protocolos ";
                sql += " INNER JOIN protocolos ON opcoes_protocolos.op_protocolo = protocolos.p_id ";
                sql += " WHERE protocolos.p_nome = \'" + protocolo + "\' AND";
                sql += " opcoes_protocolos.op_nome = \'" + argumento_protocolo + "\')";
            } else {
                sql += ", NULL";
            }

            if ((!argumento_protocolo.empty()) && (!parametro_protocolo.empty())) {
                sql += ", \'" + parametro_protocolo + "\'";
            } else {
                sql += ", NULL";
            }
        }

        sql += ", " + not_protocolo + ")";

        /*
         * realiza execução da query
         * caso operação ocorra com sucesso
         * e dado um commit na operação (confirmação)
         * limpa dados da tela de inserção
         * recarrega regras de firewall
         * e sinaliza que ouve alteração na regra
         */
        if (this->bd->query(sql.c_str())) {

            this->bd->commit();

            this->limpar_regras_firewall();
            this->trfirewall.recarregar_regras_firewall();
            this->servidor_atualizado = false;
            this->status.set_text("Regra inserida com sucesso.");

        } else {

            /*
             * Caso ocorra um erro cancela inserção no banco e
             * informa erro na inserção da regra
             */

            this->bd->rollback();

            this->mensagem("Erro ao inserir regra no firewall.", "Verifique os dados informados e tente novamente.",
                    Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
        }
    }
}

/*
 * Método utilizado para capturar dados para edição
 * de regra de firewall e mostra-los na janela de edição
 */
void INTERFACE::get_alterar_regra_firewall() {
    string sql, linha, tabela, chain, aux;
    int cont;
    vector<vector<string> >::iterator i; //interador para buscar no BD
    vector<string> valor; //recebe conteudo
    aux.clear();

    aux = this->trfirewall.get_regra_selecionada();

    /*
     * obtem linha, tabela e chain da linha selecionada
     */
    linha = this->get_conteudo_msg(aux, "<linha>", "</linha>");
    tabela = this->get_conteudo_msg(aux, "<tabela>", "</tabela>");
    chain = this->get_conteudo_msg(aux, "<chain>", "</chain>");

    /*
     * Verifica se o usuário selecionou uma regra antes de
     * clicar em alterar regras (menu superior)
     */
    if ((!linha.empty()) && (!tabela.empty()) && (!chain.empty())) {

        this->tabela.set_sensitive(false);
        this->chain.set_sensitive(false);

        this->inserir_regra.set_label(BTN_ALTERAR_REGRA);
        this->limpar_regra.set_label(BTN_CANCELAR_INS);

        sql.clear();

        /* Busca os dados para mostrar na janela criação de regras */
        sql = "SELECT rf_linha, t_nome, c_nome, ta_nome, ot_nome,"; //4
        sql += " rf_parametros_opcao, rf_endereco_origem, rf_not_endereco_origem,"; //7
        sql += " rf_endereco_destino, rf_not_endereco_destino,"; //9
        sql += " p_nome, op_nome, rf_parametros_protocolo, rf_not_protocolo, m_nome, om_nome,"; //15
        sql += " rf_parametros_modulo, rf_interface_rede, rf_interface_rede_saida_entrada, rf_not_interface_rede,"; //19
        sql += " rf_porta_origem, rf_not_porta_origem, rf_porta_destino, rf_not_porta_destino"; //23
        sql += " FROM regras_firewall";
        sql += " INNER JOIN chains_tabela ON regras_firewall.rf_chain_tabela = chains_tabela.ct_id";
        sql += " INNER JOIN tabelas ON chains_tabela.ct_tabela = tabelas.t_id";
        sql += " INNER JOIN chains ON chains_tabela.ct_chain = chains.c_id";
        sql += " INNER JOIN target ON regras_firewall.rf_target = target.ta_id";
        sql += " LEFT JOIN opcoes_target ON target.ta_id = opcoes_target.ot_target";
        sql += " AND opcoes_target.ot_id = regras_firewall.rf_opcao_target";
        sql += " LEFT JOIN opcoes_modulos ON regras_firewall.rf_modulo = opcoes_modulos.om_id";
        sql += " AND regras_firewall.rf_modulo = opcoes_modulos.om_id";
        sql += " LEFT JOIN modulos ON opcoes_modulos.om_modulo = modulos.m_id";
        sql += " LEFT JOIN protocolos ON regras_firewall.rf_protocolo = protocolos.p_id";
        sql += " LEFT JOIN opcoes_protocolos ON regras_firewall.rf_argumento_protocolo = opcoes_protocolos.op_id";
        sql += " AND protocolos.p_id = opcoes_protocolos.op_protocolo";
        sql += " WHERE regras_firewall.rf_linha = " + linha;
        sql += " AND tabelas.t_nome = \'" + tabela + "\'";
        sql += " AND chains.c_nome = \'" + chain + "\'";
        sql += " ORDER BY t_nome, c_nome, rf_linha";

        this->flag_linha = linha;

        /* realiza pesquisa e insere dados na janela de alteração */
        if (this->bd->query(sql.c_str())) {
            if (this->bd->getStatus()) {
                /* atribui os valores BD */
                i = this->bd->resultados.begin();
                valor = *i;
                for (cont = 0; cont < 24; cont++) {

                    aux = valor.at(cont);

                    if (cont == 0) {
                        this->linha.set_text(aux);
                    } else if (cont == 1) {
                        this->tabela.set_active_text(aux);
                    } else if (cont == 2) {
                        this->chain.set_active_text(aux);
                    } else if (cont == 3) {
                        this->alvo.set_active_text(aux);
                    } else if (cont == 4) {
                        this->opcao_alvo.set_active_text(aux);
                    } else if (cont == 5) {
                        this->parametros_opcao.set_text(aux);
                    } else if (cont == 6) {
                        this->endereco_origem.set_text(aux);
                    } else if (cont == 7) {
                        this->not_endereco_origem.set_active((aux == "1" ? true : false));
                    } else if (cont == 8) {
                        this->endereco_destino.set_text(aux);
                    } else if (cont == 9) {
                        this->not_endereco_destino.set_active((aux == "1" ? true : false));
                    } else if (cont == 10) {
                        this->protocolo.set_active_text(aux);
                    } else if (cont == 11) {
                        this->argumento_protocolo.set_active_text(aux);
                    } else if (cont == 12) {
                        this->parametros_protocolo.set_text(aux);
                    } else if (cont == 13) {
                        this->not_protocolo.set_active((aux == "1" ? true : false));
                    } else if (cont == 14) {
                        this->modulo.set_active_text(aux);
                    } else if (cont == 15) {
                        this->argumento_modulo.set_active_text(aux);
                    } else if (cont == 16) {
                        this->parametros_modulo.set_text(aux);
                    } else if (cont == 17) {
                        this->interface_rede_tabela.set_active_text(aux);
                    } else if (cont == 18) {
                        (aux == "o" ? this->saida.set_active(true) : this->entrada.set_active(true));
                    } else if (cont == 19) {
                        this->not_interface.set_active((aux == "1" ? true : false));
                    } else if (cont == 20) {
                        this->porta_origem.set_text(aux);
                    } else if (cont == 21) {
                        this->not_porta_origem.set_active((aux == "1" ? true : false));
                    } else if (cont == 22) {
                        this->porta_destino.set_text(aux);
                    } else if (cont == 23) {
                        this->not_porta_destino.set_active((aux == "1" ? true : false));
                    }
                }
            }
        }
    } else {
        /* caso usuário não selecione uma linha para ser altera informa erro */
        this->mensagem("Atenção", "Selecione uma linha para realizar esta operação.",
                Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_OK);
    }
}

/*
 * Método que altera regra selecionada
 */
void INTERFACE::alterar_regra_firewall() {
    string linha, tabela, chain, alvo, opcao_alvo, interface_rede_tabela, modulo, argumento_modulo, protocolo;
    string parametros_opcao, endereco_origem, endereco_destino, not_endereco_origem, not_interface;
    string not_protocolo, not_endereco_destino, argumento_protocolo, parametro_protocolo, sql;
    string porta_origem, porta_destino, not_porta_origem, not_porta_destino;

    /* Antes de alterar verifica-se regra já existe e se alguns parametros foram informados */
    if (this->existe_regra_firewall()) {

        /* obtem e valida dados antes de inserir */
        tabela = this->tabela.get_active_text();
        chain = this->chain.get_active_text();
        alvo = this->alvo.get_active_text();

        linha = this->linha.get_text();
        opcao_alvo = this->opcao_alvo.get_active_text();
        parametros_opcao = this->get_parametros_opcao_alvo();
        endereco_origem = this->get_endereco_origem();
        not_endereco_origem = (this->not_endereco_origem.get_active() && (!endereco_origem.empty()) ? "1" : "0");
        endereco_destino = this->get_endereco_destino();
        not_endereco_destino = (this->not_endereco_destino.get_active() && (!endereco_destino.empty()) ? "1" : "0");

        porta_origem = this->porta_origem.get_text();
        porta_destino = this->porta_destino.get_text();
        not_porta_origem = (this->not_porta_origem.get_active() && (!porta_origem.empty()) ? "1" : "0");
        not_porta_destino = (this->not_porta_destino.get_active() && (!porta_destino.empty()) ? "1" : "0");

        interface_rede_tabela = this->get_interface_rede_firewall();
        not_interface = (this->not_interface.get_active() && (!interface_rede_tabela.empty()) ? "1" : "0");
        modulo = this->modulo.get_active_text();
        argumento_modulo = this->argumento_modulo.get_active_text();
        protocolo = this->protocolo.get_active_text();

        argumento_protocolo = this->argumento_protocolo.get_active_text();
        parametro_protocolo = this->parametros_protocolo.get_text();

        not_protocolo = (this->not_protocolo.get_active() && (!protocolo.empty()) ? "1" : "0");

        this->bd->begin();

        /* gera script de update de regra */
        sql = "UPDATE regras_firewall SET";
        sql += " rf_target = (SELECT target.ta_id FROM target WHERE target.ta_nome = \'" + alvo + "\')";

        if (opcao_alvo.empty()) {
            sql += ", rf_opcao_target = NULL";
        } else {
            sql += ", rf_opcao_target = (SELECT ot_id FROM opcoes_target";
            sql += " INNER JOIN target ON opcoes_target.ot_target = target.ta_id";
            sql += " WHERE ta_nome = \'" + alvo + "\'";
            sql += " AND ot_nome = \'" + opcao_alvo + "\')";
        }

        sql += ", rf_parametros_opcao = " + parametros_opcao;
        sql += ", rf_endereco_origem = " + endereco_origem;
        sql += ", rf_not_endereco_origem = " + not_endereco_origem;
        sql += ", rf_porta_origem = " + (porta_origem.empty() ? "NULL" : ("\'" + porta_origem + "\'"));
        sql += ", rf_not_porta_origem = " + not_porta_origem;

        sql += ", rf_endereco_destino = " + endereco_destino;
        sql += ", rf_not_endereco_destino = " + not_endereco_destino;
        sql += ", rf_porta_destino = " + (porta_destino.empty() ? "NULL" : ("\'" + porta_destino + "\'"));
        sql += ", rf_not_porta_destino = " + not_porta_destino;

        sql += ", rf_interface_rede = " + interface_rede_tabela;
        sql += ", rf_interface_rede_saida_entrada = ";
        sql += this->get_interface_rede_saida_entrada();
        sql += ", rf_not_interface_rede = " + not_interface;

        if (modulo.empty() || argumento_modulo.empty()) {
            sql += ", rf_modulo = NULL, rf_parametros_modulo = NULL";
        } else {
            sql += ", rf_modulo = (SELECT om_id FROM opcoes_modulos ";
            sql += "INNER JOIN modulos ON opcoes_modulos.om_modulo = modulos.m_id ";
            sql += "WHERE m_nome = \'" + modulo + "\' ";
            sql += "AND om_nome = \'" + argumento_modulo + "\')";
            sql += ", rf_parametros_modulo = " + this->get_parametros_modulos();
        }

        if (protocolo.empty()) {
            sql += ", rf_protocolo = NULL, rf_argumento_protocolo = NULL, rf_parametros_protocolo = NULL";
        } else {
            sql += ", rf_protocolo = (SELECT p_id FROM protocolos WHERE protocolos.p_nome = \'" + protocolo + "\')";

            if (!argumento_protocolo.empty()) {
                sql += ", rf_argumento_protocolo = (SELECT op_id FROM opcoes_protocolos ";
                sql += " INNER JOIN protocolos ON opcoes_protocolos.op_protocolo = protocolos.p_id ";
                sql += " WHERE protocolos.p_nome = \'" + protocolo + "\' AND";
                sql += " opcoes_protocolos.op_nome = \'" + argumento_protocolo + "\')";
            } else {
                sql += ", rf_argumento_protocolo = NULL";
            }

            if ((!argumento_protocolo.empty()) && (!parametro_protocolo.empty())) {
                sql += ", rf_parametros_protocolo = \'" + parametro_protocolo + "\'";
            } else {
                sql += ", rf_parametros_protocolo = NULL";
            }
        }

        sql += ", rf_not_protocolo = " + not_protocolo;
        sql += " WHERE rf_id IN (SELECT rf_id";
        sql += " FROM regras_firewall";
        sql += " INNER JOIN chains_tabela ON regras_firewall.rf_chain_tabela = chains_tabela.ct_id";
        sql += " INNER JOIN tabelas ON chains_tabela.ct_tabela = tabelas.t_id";
        sql += " INNER JOIN chains ON chains_tabela.ct_chain = chains.c_id";
        sql += " WHERE tabelas.t_nome = \'" + tabela + "\'";
        sql += " AND chains.c_nome = \'" + chain + "\'";
        sql += " AND regras_firewall.rf_linha = " + this->flag_linha + ")";


        if (this->bd->query(sql.c_str())) {

            /*
             * caso seja necessário alterar a linha da regra
             * executa-se a linha abaixo
             */

            if ((this->flag_linha != linha) && (linha != "0")) {
                sql.clear();

                sql = "UPDATE regras_firewall";

                /* move regra para baixo */
                if (atoi(this->flag_linha.c_str()) < atoi(linha.c_str())) {
                    sql += " SET rf_linha = CASE WHEN rf_linha > " + this->flag_linha;
                    sql += " AND rf_linha <= " + linha + " THEN rf_linha - 1";
                }

                /* move regra para cima */
                if (atoi(this->flag_linha.c_str()) > atoi(linha.c_str())) {
                    sql += " SET rf_linha = CASE WHEN rf_linha < " + this->flag_linha;
                    sql += " AND rf_linha >= " + linha + " THEN rf_linha + 1";
                }

                sql += " WHEN rf_linha = " + this->flag_linha + " THEN ";

                sql += " (SELECT CASE WHEN MAX(rf_linha) < " + linha + " THEN MAX(rf_linha)";
                sql += " ELSE " + linha + " END AS linha";
                sql += " FROM regras_firewall";
                sql += " INNER JOIN chains_tabela ON regras_firewall.rf_chain_tabela = chains_tabela.ct_id";
                sql += " INNER JOIN tabelas ON chains_tabela.ct_tabela = tabelas.t_id";
                sql += " INNER JOIN chains ON chains_tabela.ct_chain = chains.c_id";
                sql += " WHERE tabelas.t_nome = \'" + tabela + "\'";
                sql += " AND chains.c_nome = \'" + chain + "\')";

                sql += " ELSE rf_linha END";
                sql += " WHERE rf_id IN";

                sql += " (SELECT rf_id";
                sql += " FROM regras_firewall";
                sql += " INNER JOIN chains_tabela ON regras_firewall.rf_chain_tabela = chains_tabela.ct_id";
                sql += " INNER JOIN tabelas ON chains_tabela.ct_tabela = tabelas.t_id";
                sql += " INNER JOIN chains ON chains_tabela.ct_chain = chains.c_id";
                sql += " WHERE tabelas.t_nome = \'" + tabela + "\'";
                sql += " AND chains.c_nome = \'" + chain + "\')";

                if (!this->bd->query(sql.c_str())) {
                    /* caso ocorra um erro cancela alterações */
                    this->bd->rollback();
                } else {
                    this->bd->commit();
                    this->servidor_atualizado = false;
                }
            } else {
                /* Caso não seja necessário alterar regra grava alterações */
                this->bd->commit();
                this->servidor_atualizado = false;
            }

            this->limpar_regras_firewall();
            this->trfirewall.recarregar_regras_firewall();

        } else {
            this->bd->rollback();
        }

    }
}

/*
 * Método exclui regras do firewall
 */
void INTERFACE::excluir_regra_firewall() {
    string sql, tabela, chain, linha;
    bool permitido = false;

    sql.clear();
    tabela.clear();
    chain.clear();
    linha.clear();

    /* não permite a exclusão de política padrão */
    if (this->politica_padrao.get_active()) {
        this->mensagem("Atenção", "Não é permitido a operação de exclusão da política padrão, somente alteração.",
                Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_OK);
    } else {
        /* Solicita permição do usuário para excluir regra */
        permitido = this->mensagem("Atenção", "Deseja Excluir esta regra?", Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_OK_CANCEL);
    }


    if (permitido) {
        /* Caso o usuário clique em "OK" realiza captura de dados para exclusão */
        sql.clear();
        sql = this->trfirewall.get_regra_selecionada();

        tabela = this->get_conteudo_msg(sql, "<tabela>", "</tabela>");
        chain = this->get_conteudo_msg(sql, "<chain>", "</chain>");
        linha = this->get_conteudo_msg(sql, "<linha>", "</linha>");

        /* Verifica se o usuário selecionou uma linha para excluir */
        if ((!tabela.empty()) && (!chain.empty()) && (!linha.empty())) {

            this->bd->begin();

            sql = "DELETE FROM regras_firewall WHERE regras_firewall.rf_id IN (SELECT rf_id";
            sql += " FROM regras_firewall";
            sql += " INNER JOIN chains_tabela ON regras_firewall.rf_chain_tabela = chains_tabela.ct_id";
            sql += " INNER JOIN tabelas ON chains_tabela.ct_tabela = tabelas.t_id";
            sql += " INNER JOIN chains ON chains_tabela.ct_chain = chains.c_id";
            sql += " WHERE tabelas.t_nome = \'" + tabela + "\'";
            sql += " AND chains.c_nome = \'" + chain + "\'";
            sql += " AND regras_firewall.rf_linha = " + linha + ")";

            this->bd->query(sql.c_str());

            this->bd->commit();

            this->limpar_regras_firewall();
            this->trfirewall.recarregar_regras_firewall();
            this->servidor_atualizado = false;
        } else {

            /* Informa mensagem de erro caso o usuário não selecione uma linha */
            this->mensagem("Atenção", "Selecione uma linha para realizar esta operação.",
                    Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_OK);
        }

    }
}

/*
 * Método que realiza o envio das regras criadas para o servidor
 */
void INTERFACE::upload_regras_firewall() {
    string sql, aux;
    int cont = 0;
    vector<vector<string> >::iterator i; //interador para buscar no BD
    vector<string> valor; //recebe conteudo

    if (this->conectar_servidor(this->usuario_fw, this->senha_fw, this->servidor_fw)) {

        /* "Sinaliza" que será enviados o dados gerados no cliente */
        send(this->sock, "<mensagem><comando></mensagem>", BUFFER_SERVIDOR, MSG_WAITALL);

        sql.clear();

        /* Atráves de comandos SQL e gerado os comando de inserção de regras */
        sql = "SELECT  'INSERT INTO regras_firewall VALUES(' || rf_id || ', ' || rf_linha || ', ' || rf_chain_tabela || ', ' || ";
        sql += "rf_target || ', ' || CASE WHEN rf_opcao_target IS NULL THEN 'NULL' ELSE rf_opcao_target END || ', ' || ";
        sql += "CASE WHEN rf_parametros_opcao IS NULL THEN 'NULL' ELSE '\"' || rf_parametros_opcao || '\"' END || ', ' || ";
        sql += "CASE WHEN rf_endereco_origem IS NULL THEN 'NULL' ELSE '\"' || rf_endereco_origem || '\"' END || ', ' || ";
        sql += "rf_not_endereco_origem || ', ' || ";
        sql += "CASE WHEN rf_porta_origem IS NULL THEN 'NULL' ELSE '\"' || rf_porta_origem || '\"' END || ', ' || ";
        sql += "rf_not_porta_origem || ', ' || ";
        sql += "CASE WHEN rf_endereco_destino IS NULL THEN 'NULL' ELSE '\"' || rf_endereco_destino || '\"' END || ', ' || ";
        sql += "rf_not_endereco_destino || ', ' || ";
        sql += "CASE WHEN rf_porta_destino IS NULL THEN 'NULL' ELSE '\"' || rf_porta_destino || '\"' END || ', ' || ";
        sql += "rf_not_porta_destino || ', ' || ";
        sql += "CASE WHEN rf_interface_rede IS NULL THEN 'NULL' ELSE '\"' || rf_interface_rede || '\"' END || ', ' || ";
        sql += "CASE WHEN rf_interface_rede_saida_entrada IS NULL THEN 'NULL' ELSE '\"' || rf_interface_rede_saida_entrada || '\"' END || ', ' || ";
        sql += "rf_not_interface_rede || ', ' || ";
        sql += "CASE WHEN rf_modulo IS NULL THEN 'NULL' ELSE rf_modulo END || ', ' || ";
        sql += "CASE WHEN rf_parametros_modulo IS NULL THEN 'NULL' ELSE '\"' || rf_parametros_modulo || '\"' END || ', ' || ";
        sql += "CASE WHEN rf_protocolo IS NULL THEN 'NULL' ELSE rf_protocolo END || ', ' || ";
        sql += "CASE WHEN rf_argumento_protocolo IS NULL THEN 'NULL' ELSE rf_argumento_protocolo END || ', ' || ";
        sql += "CASE WHEN rf_parametros_protocolo IS NULL THEN 'NULL' ELSE '\"' || rf_parametros_protocolo || '\"' END || ', ' || ";
        sql += "rf_not_protocolo || ')' ";
        sql += "FROM regras_firewall ";
        sql += "UNION ";
        sql += "SELECT 'UPDATE chains_tabela SET ct_politica = ' || ct_politica  || ' WHERE ct_id = ' || ct_id FROM chains_tabela ";

        this->bd->query(sql.c_str());

        if (this->bd->getStatus()) {
            /* captura dados gerados pela consulta */
            for (i = this->bd->resultados.begin(); i < this->bd->resultados.end(); i++) {
                valor = *i;

                aux = valor.at(cont);

                /* Envia comando aos servidor */
                send(this->sock, aux.c_str(), BUFFER_SERVIDOR, MSG_WAITALL);
            }
        }

        /* "Sinaliza" o fim da inserção de comandos */
        if (send(this->sock, "<mensagem><fim_sql></comando>", BUFFER_SERVIDOR, MSG_WAITALL) > 0) {
            this->mensagem("Informação", "Regras enviadas com sucesso ao servidor.",
                    Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK);
        }

        /* Fecha conexão com servidor após realizar upload de regras */
        close(this->sock);

        this->servidor_atualizado = true;
    } else {
        this->mensagem("Falha", "Falha ao conectar com servidor Firewall. Tente mais tarde.", Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
    }
}

/*
 * Método que captura dados para filtragem e cria thead
 * para preencher a treeview com as informações dos dados capturados
 */
void INTERFACE::executa_filtro() {
    int count;
    string interfac, regra, quant, consulta;

    interfac = this->interface_rede_fp.get_active_text();
    regra = this->regra_fp.get_active_text();
    regra = (regra.empty() ? "vazio" : regra);
    quant = this->quant_fp.get_text();

    count = atoi(quant.c_str());

    if (this->conectar_servidor(this->usuario_fw, this->senha_fw, this->servidor_fw)) {

        consulta = "<mensagem><captura><interface>" + interfac + "</interface>";
        consulta += "<filtro>" + regra + "</filtro>";
        consulta += "<qtpacotes>" + quant + "</qtpacotes></captura></mensagem>";

        sprintf(this->msg, "%s", consulta.c_str());

        /*
         * Cria thread para inserção de dados na treeview
         */
        this->thread = Glib::Thread::create(sigc::bind(sigc::mem_fun<char*, int>(*this, &INTERFACE::thread_filtro_pacotes), this->msg, count));

        /*
         * Desabilita inserção de uma nova regra
         */
        this->interface_rede_fp.set_sensitive(false);
        this->regra_fp.set_sensitive(false);
        this->quant_fp.set_sensitive(false);
        this->ok_fp.set_sensitive(false);
        this->recarregar_regras_firewall.set_sensitive(false);
    } else {
        this->mensagem("Falha", "Falha ao conectar com servidor Firewall. Tente mais tarde.", Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
    }
}

/*
 * Método utilizado pela thread para preencher a treeview
 * filtro String com especificação do filtro de pacote
 * quantidade Quantidade de pacotes a ser capturado
 */
void INTERFACE::thread_filtro_pacotes(char *filtro, int quantidade) {
    int tam;
    string aux, sql, interfac, buffer;
    banco *bd;

    /* Envia comando regra e quantidade de pacotes a ser capturados */
    tam = send(this->sock, filtro, BUFFER_SERVIDOR, MSG_WAITALL);

    this->status_filtro = true;

    interfac = this->interface_rede_fp.get_active_text();

    if (tam > 0) {
        bd = new banco(FILE_DB_FILTER);
        bd->begin();

        tam = quantidade;

        this->active_thread = !this->active_thread;

        while (quantidade-- > -1) {

            recv(this->sock, filtro, BUFFER_SERVIDOR, MSG_WAITALL);

            /*
             * Ao terminar o envia de dados um mensagem de fim e enviada
             */
            if (strcmp(filtro, "<mensagem><fim_captura></mensagem>") == 0) {
                break;
            }

            buffer.clear();
            buffer.append(filtro);

            /*
             * Verifica se a alguma mensagem de erro
             * caso não haja extrai os dados recebidos
             * e insere os dados na treeview
             */
            if (strncmp(filtro, "<mensagem><error>", 17) != 0) {

                sql = "INSERT INTO pacotes_filtro VALUES(";
                sql += "\'" + interfac + "\', ";
                sql += "\'" + this->get_conteudo_msg(buffer, "<srcip>", "</srcip>") + "\', ";
                aux = this->get_conteudo_msg(buffer, "<srcport>", "</srcport>");
                sql += (aux.empty() ? "0" : aux) + ", ";
                sql += "\'" + this->get_conteudo_msg(buffer, "<dstip>", "</dstip>") + "\', ";
                aux = this->get_conteudo_msg(buffer, "<dstport>", "</dstport>");
                sql += (aux.empty() ? "0" : aux) + ", ";
                sql += "\'" + this->get_conteudo_msg(buffer, "<proto>", "</proto>") + "\')";

                if (!(quantidade % 250)) {
                    bd->commit();
                    bd->begin();
                }

                bd->query(sql.c_str());
            } else {

                this->status_filtro = false;
            }
        }

        /*
         * Remove as linhas inseridas na tabela pacotes_filtros
         * pois as mesma a partir deste momento são desnecessárias
         * pois já foi feito o "resumo dos pacotes" via triggers
         */
        bd->query("DELETE FROM pacotes_filtros;");

        bd->commit();
        delete bd;
    }

    /*
     * Ao encerrar execução chama despachente
     * que habilita nova solicitação de capturas
     */
    this->dispatcher();
}

/*
 * Método despachante que reabilita janela de inserção de uma
 * nova regra de filtragem
 */
void INTERFACE::exec_dispatcher() {
    string sql;
    vector<vector<string> >::iterator i; //interador para buscar no BD
    vector<string> valor; //recebe conteudo

    sql = this->regra_fp.get_active_text();

    this->thread->join();

    /* fecha conexão com servidor após realizar filtragem de pacotes */
    close(this->sock);

    /*
     * caso ocorra algum erro durante a captura de pacotes é
     * exibido um mensagem de erro
     */
    if (!this->status_filtro) {
        this->mensagem(
                "Erro ao executar a filtragem de pacotes.",
                "Verifique dados da filtragem e tente novamente.",
                Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
    } else if (!sql.empty()) {
        /*
         * caso não ocorra nenhum erro e tenha inserido uma
         * regra esta e verificada se já existe e é armazenada
         * no banco de dados para auxiliar o usuário futuramente
         */
        sql.clear();

        sql = "SELECT EXISTS(SELECT rf_id FROM regras_filtro WHERE rf_regra=\'" + this->regra_fp.get_active_text() + "\')";

        this->bd->query(sql.c_str());

        if (this->bd->getStatus()) {
            /* atribui os valores BD */
            i = this->bd->resultados.begin();
            valor = *i;
            if (valor.at(0) == "0") {

                sql = "INSERT INTO regras_filtro (\'rf_id\', \'rf_regra\') VALUES (NULL, \'";
                sql += this->regra_fp.get_active_text();
                sql += "\')";
                this->bd->query(sql.c_str());
            }
        }


    }

    this->trfilter.content_filter();

    /*
     * Habilita botões e area de texto
     */
    this->interface_rede_fp.set_sensitive(true);
    this->regra_fp.set_sensitive(true);
    this->quant_fp.set_sensitive(true);
    this->ok_fp.set_sensitive(true);
    this->recarregar_regras_firewall.set_sensitive(true);
}

/*
 * Método que extrai conteudo de uma mensagem
 * comeco Inicio da tag
 * fim Fim da tag
 * Retorna o conteudo dentro da tag. Ou vazio caso não encontre a tag.
 */
string INTERFACE::get_conteudo_msg(string msg, string comeco, string fim) {
    std::size_t inicio, tamanho;

    inicio = msg.find(comeco) + comeco.length();
    tamanho = msg.find(fim);

    /* Verifica se o conteudo foi encontrado */
    if ((inicio != std::string::npos) && (tamanho != std::string::npos)) {

        return msg.substr(inicio, tamanho - inicio);
    }

    return "";
}

/*
 * Método chamado ao encerrar aplicação
 * para verificar se os dados foram enviado ao servidor
 */
void INTERFACE::encerrar() {
    bool ok;

    /* Verifica se as regras recem criada já foram "salvas" no servidor */
    if (!this->servidor_atualizado) {
        ok = this->mensagem("Atenção", "Deseja salvar as alterações antes de sair?", Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO);

        /* caso o usuário clique em sim realiza atualização das regras do servidor */
        if (ok) {
            this->upload_regras_firewall();
        }
    }

    this->dialog_login.hide();
    this->cliente_fw.hide();
}

/*
 * Método que recebe dados da linha seleciona da treeview
 * e insere na janela de criação de regra do firewall
 */
void INTERFACE::create_by_row_filter() {
    string msg = this->trfilter.create_by_row();

    if (!msg.empty()) {

        /* captura dados da linha selecionada */
        this->protocolo.set_active_text(this->get_conteudo_msg(msg, "<protocolo>", "</protocolo>"));
        this->endereco_origem.set_text(this->get_conteudo_msg(msg, "<origem>", "</origem>"));
        this->porta_origem.set_text(this->get_conteudo_msg(msg, "<portOrigem>", "</portOrigem>"));
        this->endereco_destino.set_text(this->get_conteudo_msg(msg, "<destino>", "</destino>"));
        this->porta_destino.set_text(this->get_conteudo_msg(msg, "<portDestino>", "</portDestino>"));
        this->interface_rede_tabela.set_active_text(this->get_conteudo_msg(msg, "<interface>", "</interface>"));
    }
}

/*
 * Método que remove as todas as linha do resultado da filtragem
 */
void INTERFACE::delete_row_filter() {
    bool ok;

    ok = this->mensagem("Atenção", "Deseja remover todos os resultados da filtragem", Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK_CANCEL);
    if (ok) {
        this->trfilter.delete_row();
    }
}

/*
 * Método que filtra resultados da filtragem
 * a partir de uma linha selecionada
 */
void INTERFACE::exec_filter_result() {
    string filter;

    filter = this->filter_result.get_active_text();

    /*verifica se o usuário selecionou uma opção e realiza a filtragem */
    if (!filter.empty()) {
        this->trfilter.reorder_row(filter);
    } else {
        this->mensagem("Erro ao filtrar Resultados.", "Selecione uma opção e tente novamente",
                Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
    }
}

